package com.jwater.core.manager.common.conf;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwater.core.common.IpPort;
import com.jwater.core.common.param.ParamMap;
import com.jwater.core.common.xml.XmlConfig;
import com.jwater.core.manager.common.model.CoreConfigInfo;
import com.jwater.core.manager.common.model.NodeInfo;
import com.jwater.core.manager.common.model.ProxyInfo;
import com.jwater.core.metrics.SystemMetric;
import com.jwater.core.net.group.Member;
import com.jwater.launch.HomePath;

/**
 * @description: 核心配置解析器
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class CoreConfParse {
    protected static Logger logger = LoggerFactory.getLogger(CoreConfParse.class);
    protected volatile CoreConfigInfo configInfo = new CoreConfigInfo();

    /**
     * 获取CoreConfigInfo对象，循环获取，防止重新赋值的一瞬间获取空值
     *
     * @return
     */
    public CoreConfigInfo getCoreConfigInfo() {
        // 重新parse时赋值防止为空
        while (configInfo == null) {
        }
        return configInfo;
    }

    /**
     * 获取所有的代理配置
     *
     * @return
     */
    public List<ProxyInfo> getProxyInfos() {
        List<ProxyInfo> infos = new ArrayList<ProxyInfo>();
        for (Entry<String, Object> en : getCoreConfigInfo().getProxys().entrySet()) {
            ProxyInfo proxyInfo = new ProxyInfo();
            proxyInfo.setHost(en.getKey().toString());
            proxyInfo.setPort(Integer.parseInt(en.getValue().toString()));
            infos.add(proxyInfo);
        }
        return infos;
    }

    /**
     * 获取本地代理
     *
     * @return
     */
    public ProxyInfo getLocalProxyInfo() {
        List<ProxyInfo> infos = getProxyInfos();
        Map<String, String> localHosts = SystemMetric.getHosts();
        for (ProxyInfo info : infos) {
            if (localHosts.containsValue(info.getHost())) {
                return info;
            }
        }
        return null;
    }

    /**
     * 获取所有管理进程的配置
     *
     * @return
     */
    public List<Member> getMembers() {
        List<Member> members = new ArrayList<Member>();
        try {
            for (Entry<String, Object> en : getCoreConfigInfo().getMasters().entrySet()) {
                if (en.getKey().startsWith("master.")) {
                    String[] items = en.getValue().toString().trim().split(":");
                    Member member = new Member();
                    member.setMemberId(Integer.parseInt(en.getKey().replace("master.", "").trim()));
                    NodeInfo nodeInfo = getNodeInfo(items[0], items[1]);
                    if (nodeInfo == null) {
                        throw new ConfParseException("can not find node info for:" + items[0] + ":" + items[1]);
                    }
                    member.setNodeInfo(nodeInfo);
                    member.setIp(nodeInfo.getHost());
                    member.setInnerPort(Integer.parseInt(items[2]));
                    member.setOuterPort(Integer.parseInt(items[3]));
                    members.add(member);
                }
            }
        } catch (Exception e) {
            throw new ConfParseException("parse core master conf error", e);
        }
        return members;
    }

    /**
     * 获取管理进程的配置
     *
     * @param index
     * @return
     */
    public Member getMember(int index) {
        List<Member> members = getMembers();
        for (Member member : members) {
            if (member.getMemberId() == index) {
                return member;
            }
        }
        return null;
    }

    /**
     * 获取管理进程的主机
     *
     * @return
     */
    public List<IpPort> getMasterHosts() {
        List<IpPort> masterHosts = new ArrayList<IpPort>();
        List<Member> members = getMembers();
        for (Member member : members) {
            masterHosts.add(new IpPort(member.getIp(), member.getOuterPort()));
        }
        return masterHosts;
    }

    /**
     * 获取所有的主机信息
     *
     * @return
     */
    public List<NodeInfo> getNodeList() {
        Set<String> hosts = new HashSet<String>();
        List<NodeInfo> list = new ArrayList<NodeInfo>();
        for (Entry<String, Map<String, NodeInfo>> en1 : getCoreConfigInfo().getNodes().entrySet()) {
            for (Entry<String, NodeInfo> en2 : en1.getValue().entrySet()) {
                if (!hosts.contains(en2.getValue().getHost())) {
                    hosts.add(en2.getValue().getHost());
                }
                list.add(en2.getValue());
            }
        }
        return list;
    }

    /**
     * 获取主机信息
     *
     * @param groupName
     * @return
     */
    public List<NodeInfo> getNodeList(String groupName) {
        List<NodeInfo> list = new ArrayList<NodeInfo>();
        Map<String, NodeInfo> nodes = getCoreConfigInfo().getNodes().get(groupName);
        if (nodes != null) {
            nodes.forEach((key, node) -> {
                list.add(node);
            });
        }
        return list;
    }

    /**
     * 获取主机信息
     *
     * @param groupName
     * @param nodeName
     * @return
     */
    public List<NodeInfo> getNodeList(String groupName, String nodeName) {
        List<NodeInfo> list = new ArrayList<NodeInfo>();
        Map<String, NodeInfo> nodes = getCoreConfigInfo().getNodes().get(groupName);
        if (nodes != null) {
            NodeInfo node = nodes.get(nodeName);
            if (node != null) {
                list.add(node);
            }
        }
        return list;
    }

    /**
     * 获取主机信息
     *
     * @param host
     * @return
     */
    public NodeInfo getNodeInfo(String host) {
        List<NodeInfo> nodeInfos = getNodeList();
        for (NodeInfo nodeInfo : nodeInfos) {
            if (host.equals(nodeInfo.getHost())) {
                return nodeInfo;
            }
        }
        return null;
    }

    /**
     * 获取主机信息
     *
     * @param groupName
     * @param nodeName
     * @return
     */
    public NodeInfo getNodeInfo(String groupName, String nodeName) {
        Map<String, NodeInfo> nodes = getCoreConfigInfo().getNodes().get(groupName);
        if (nodes != null) {
            return nodes.get(nodeName);
        }
        return null;
    }

    /**
     * 获取本地主机信息
     *
     * @return
     */
    public NodeInfo getLocalNodeInfo() {
        Map<String, String> localHosts = SystemMetric.getHosts();
        List<NodeInfo> nodes = getNodeList();
        for (NodeInfo node : nodes) {
            if (localHosts.containsValue(node.getHost())) {
                return node;
            }
        }
        return null;
    }

    /**
     * 获取集群名称
     *
     * @return
     */
    public String getClusterName() {
        return getCoreConfigInfo().getProps().getString("clusterName", "default");
    }

    /**
     * 获取控制台jvm配置
     *
     * @return
     */
    public String getConsoleJvmArgs() {
        return getCoreConfigInfo().getProps().getString("consoleJvm", "-Xmx1g");
    }

    /**
     * 获取管理进程jvm配置
     *
     * @return
     */
    public String getMasterJvmArgs() {
        return getCoreConfigInfo().getProps().getString("masterJvm", "-Xmx1g");
    }

    /**
     * 获取代理进程jvm配置
     *
     * @return
     */
    public String getProxyJvmArgs() {
        return getCoreConfigInfo().getProps().getString("proxyJvm", "-Xmx1g");
    }

    /**
     * 获取平台名称
     *
     * @return
     */
    public String getPlatName() {
        return getCoreConfigInfo().getProps().getString("platName", "JWATER CLOUD DEPLOYMENT");
    }

    /**
     * 获取端口访问定义
     *
     * @return
     */
    public int[] getWorkerPortRange() {
        String[] items = getCoreConfigInfo().getProps().getString("workerPort.range", "10000,20000").split(",");
        return new int[]{Integer.parseInt(items[0]), Integer.parseInt(items[1])};
    }

    /**
     * 磁盘大小限制
     *
     * @return
     */
    public double getDiskLimit() {
        String diskLimit = getCoreConfigInfo().getProps().getString("diskLimit", "5G");
        if (diskLimit.endsWith("G")) {
            return Double.parseDouble(diskLimit.replace("G", ""));
        }
        if (diskLimit.endsWith("M")) {
            return Double.parseDouble(diskLimit.replace("M", "")) / 1024;
        }
        return Double.parseDouble(diskLimit);
    }

    /**
     * 内存限制
     *
     * @return
     */
    public double getMemLimit() {
        String limit = getCoreConfigInfo().getProps().getString("memLimit", "2G");
        if (limit.endsWith("G")) {
            return Double.parseDouble(limit.replace("G", "")) * 1024;
        }
        if (limit.endsWith("M")) {
            return Double.parseDouble(limit.replace("M", ""));
        }
        return Double.parseDouble(limit);
    }

    /**
     * cpu限制
     *
     * @return
     */
    public double getCpuLimit() {
        String limit = getCoreConfigInfo().getProps().getString("cpuLimit", "80%");
        if (limit.endsWith("%")) {
            return Double.parseDouble(limit.replace("%", "")) / 100;
        }
        return Double.parseDouble(limit) / 100;
    }

    /**
     * 可以重复解析
     */
    public void parse() {
        try {
            CoreConfigInfo coreConfigInfo = new CoreConfigInfo();
            XmlConfig config = new XmlConfig();
            config.loadConfig(HomePath.getCorePath());
            parseNode(coreConfigInfo, config);
            parseMasters(coreConfigInfo, config);
            parseProxys(coreConfigInfo, config);
            parseProps(coreConfigInfo, config);
            parseLogin(coreConfigInfo, config);
            this.configInfo = coreConfigInfo;
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
    }

    /**
     * @param coreConfigInfo
     * @param config
     */
    private void parseNode(CoreConfigInfo coreConfigInfo, XmlConfig config) {
        List<ParamMap> nodesPms = config.getParamMapsByPath("jwater/nodes");
        if (nodesPms == null) {
            return;
        }
        for (ParamMap nodesPm : nodesPms) {
            Map<String, NodeInfo> map = new ConcurrentHashMap<>();
            String groupName = nodesPm.getString("groupName");
            List<ParamMap> nodePms = nodesPm.getParamMaps("node");
            for (ParamMap nodePm : nodePms) {
                NodeInfo nodeInfo = new NodeInfo();
                nodeInfo.setGroupName(groupName);
                nodeInfo.setNodeName(nodePm.getString("nodeName"));
                nodeInfo.setHost(nodePm.getString("host"));
                nodeInfo.setPort(nodePm.getInt("port"));
                nodeInfo.setUsername(nodePm.getString("username"));
                nodeInfo.setPassword(nodePm.getString("password"));
                nodeInfo.setType(nodePm.getString("type"));
                nodeInfo.setPath(nodePm.getString("path"));
                nodeInfo.setSsh(nodePm.getString("ssh", "true"));
                map.put(nodeInfo.getNodeName(), nodeInfo);
            }
            coreConfigInfo.getNodes().put(groupName, map);
        }
    }

    /**
     * 解析管理进程
     *
     * @param coreConfigInfo
     * @param config
     */
    private static void parseMasters(CoreConfigInfo coreConfigInfo, XmlConfig config) {
        List<ParamMap> props = config.getParamMapsByPath("jwater/masters/master");
        if (props == null) {
            return;
        }
        for (ParamMap prop : props) {
            coreConfigInfo.getMasters().put(prop.getString("key"), prop.getString("value"));
        }
    }

    /**
     * 解析代理进程
     *
     * @param coreConfigInfo
     * @param config
     */
    private static void parseProxys(CoreConfigInfo coreConfigInfo, XmlConfig config) {
        List<ParamMap> props = config.getParamMapsByPath("jwater/proxys/proxy");
        if (props == null) {
            return;
        }
        for (ParamMap prop : props) {
            coreConfigInfo.getProxys().put(prop.getString("key"), prop.getString("value"));
        }
    }

    /**
     * 解析属性
     *
     * @param coreConfigInfo
     * @param config
     */
    private static void parseProps(CoreConfigInfo coreConfigInfo, XmlConfig config) {
        List<ParamMap> props = config.getParamMapsByPath("jwater/props/prop");
        if (props == null) {
            return;
        }
        for (ParamMap prop : props) {
            coreConfigInfo.getProps().put(prop.getString("key"), prop.getString("value"));
        }
    }

    /**
     * 解析登录信息
     *
     * @param coreConfigInfo
     * @param config
     */
    private void parseLogin(CoreConfigInfo coreConfigInfo, XmlConfig config) {
        List<ParamMap> loginPms = config.getParamMapsByPath("jwater/logins/login");
        if (loginPms == null) {
            return;
        }
        for (ParamMap loginPm : loginPms) {
            String region = loginPm.getString("region");
            String username = loginPm.getString("username");
            String password = loginPm.getString("password");
            coreConfigInfo.getLogins().put(region + "," + username, password);
        }
    }
}
